﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
namespace WITD
{
    /// <summary>
    /// Includes methods to work with project iterations.
    /// </summary>
    class Iteration
    {

        /// <summary>
        /// Gets the iteration nodes for the specified project.
        /// </summary>
        /// <param name="collection">The team project collection that houses the project.</param>
        /// <param name="projectName">The name of the project from which to get the iteration nodes.</param>
        /// <returns>A Dictionary object with the project's iteration nodes.</returns>
        public Dictionary<string, string> GetProjectIterations(TfsTeamProjectCollection collection, string projectName)
        {
            Dictionary<string, string> results = new Dictionary<string, string>();

            ICommonStructureService commonStructure = collection.GetService(typeof(ICommonStructureService)) as ICommonStructureService;
            ProjectInfo project = commonStructure.GetProjectFromName(projectName);

            foreach (NodeInfo node in commonStructure.ListStructures(project.Uri))
            {
                if (node.StructureType == "ProjectLifecycle")
                {
                    XmlElement nodeElement = commonStructure.GetNodesXml(new string[] { node.Uri }, true);
                    AddChildNodes(node.Name, nodeElement.ChildNodes[0], results);
                }
            }
            return results;
        }

        /// <summary>
        /// Adds the specified node and all its child nodes to the specified dictionary object.
        /// </summary>
        /// <param name="parentPath">The parent nodes XML path.</param>
        /// <param name="parentNode">The parent XmlNode to add.</param>
        /// <param name="results">The Dictionary object to which to add the nodes.</param>
        private void AddChildNodes(string parentPath, XmlNode parentNode, Dictionary<string, string> results)
        {
            results.Add(parentPath, parentNode.Attributes["NodeID"].Value);
            if (parentNode.ChildNodes[0] == null)
                return;

            foreach (XmlNode node in parentNode.ChildNodes[0].ChildNodes)
            {
                string nodePath = node.Attributes["Path"].Value;
                AddChildNodes(nodePath, node, results);
            }
        }
        
        /// <summary>
        /// Creates the specified iteration node in the specified project structure under the specified node.
        /// </summary>
        /// <param name="css">The structure service in which the project resides.</param>
        /// <param name="nodeName">The name of the node to create.</param>
        /// <param name="rootNode">The new node's root.</param>
        private void CreateNode(ICommonStructureService css, string nodeName, NodeInfo rootNode)
        {
            if (!nodeName.Contains("\\"))
            {
                if (!NodeExists(css, nodeName, rootNode))
                {
                    css.CreateNode(nodeName, rootNode.Uri);
                }
            }
            else
            {
                int lastBackslash = nodeName.LastIndexOf("\\");
                NodeInfo info = css.GetNodeFromPath(rootNode.Path + "\\" + nodeName.Substring(0, lastBackslash));
                css.CreateNode(nodeName.Substring(lastBackslash + 1), info.Uri);
            }
        }

        /// <summary>
        /// Exports the iteration nodes from the specified project to a MemoryStream object.
        /// </summary>
        /// <param name="collection">The collection in which the team project resides.</param>
        /// <param name="project">The team project from which to export iteration nodes.</param>
        /// <returns>The MemoryStream to which the iteration nodes were exported.</returns>
        public MemoryStream ExportIterationNodes(TfsTeamProjectCollection collection, Project project)
        {
            ICommonStructureService css = (ICommonStructureService)collection.GetService(typeof(ICommonStructureService));

            MemoryStream fs = new MemoryStream();
            StreamWriter writer = new StreamWriter(fs);
            
            WriteNodes(project.IterationRootNodes, writer, "I");
            writer.Flush();
            return fs;
        }

        /// <summary>
        /// Writes the specified nodes to the specified stream.
        /// </summary>
        /// <param name="nodes">The nodes to write.</param>
        /// <param name="writer">The StreamWriter instance to which to write.</param>
        /// <param name="prefix">The prefix string to write.</param>
        private void WriteNodes(NodeCollection nodes, StreamWriter writer, string prefix)
        {

            foreach (Node node in nodes)
            {
                writer.Write(prefix);
                writer.WriteLine(node.Path.Substring(node.Path.IndexOf(@"\")));

                if (node.ChildNodes.Count > 0)
                {
                    WriteNodes(node.ChildNodes, writer, prefix);
                }
            }
        }

        /// <summary>
        /// Imports the iteration nodes stored in the passed MemoryStream into the specified project.
        /// </summary>
        /// <param name="collection">The collection where the project resides.</param>
        /// <param name="ms">The MemoryStream instance in which the nodes to import are stored..</param>
        /// <param name="project">The team project in which to import the iteration nodes.</param>
        /// <param name="options">The options that dictate how to copy the nodes.</param>
        public void ImportIterationNodes(TfsTeamProjectCollection collection, MemoryStream ms, Project project, IterationCopyOptions options)
        {
            NodeInfo rootAreaNode = null;
            NodeInfo rootIterationNode = null;

            ICommonStructureService css = (ICommonStructureService)collection.GetService(typeof(ICommonStructureService));

            
            foreach (NodeInfo info in css.ListStructures(project.Uri.ToString()))
            {
                if (info.StructureType == "ProjectModelHierarchy")
                {
                    rootAreaNode = info;
                }
                else if (info.StructureType == "ProjectLifecycle")
                {
                    rootIterationNode = info;
                }
            }

            if (options.Options == IterationOptions.OverwriteAll) { DeleteIterations(collection, project); }

            using (StreamReader reader = new StreamReader(ms))
            {
                string nextLine;
                ms.Seek(0, 0);

                while (!reader.EndOfStream)
                {
                    nextLine = reader.ReadLine();
                    if (nextLine.StartsWith("I"))
                    {
                        CreateNode(css, nextLine.Substring(2), rootIterationNode);
                    }
                    else
                    { // Ignore other lines
                    }
                }
            }
        }

        /// <summary>
        /// Determines if the specified node exists in the specified project structure.
        /// </summary>
        /// <param name="css">The structure service to query.</param>
        /// <param name="nodeName">The name of the node for which to search.</param>
        /// <param name="rootNode">The root in which to search.</param>
        /// <returns>True if a node with the specified name is found in the root node hierarchy. Otherwise false.</returns>
        private bool NodeExists(ICommonStructureService css, string nodeName, NodeInfo rootNode)
        {
            try
            {
                NodeInfo node = css.GetNodeFromPath(rootNode.Path.ToString() + "\\" + nodeName);

                if (node != null)
                {
                    return true;
                }
                else
                {
                    //this will never happen
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Deletes all iteration nodes from the specified project.
        /// </summary>
        /// <param name="collection">The collection in which the project resides.</param>
        /// <param name="project">The team project from which to delete the iteration nodes.</param>
        private void DeleteIterations(TfsTeamProjectCollection collection, Project project)
        {
            NodeInfo rootIterationNode = null;

            if (project != null)
            {
                ICommonStructureService css = (ICommonStructureService)collection.GetService(typeof(ICommonStructureService));
                foreach (NodeInfo info in css.ListStructures(project.Uri.ToString()))
                {
                    if (info.StructureType == "ProjectLifecycle")
                    {
                        rootIterationNode = info;
                        XmlElement nodeElement = css.GetNodesXml(new string[] { rootIterationNode.Uri }, true);
                        foreach (XmlNode node in nodeElement.ChildNodes[0].ChildNodes[0].ChildNodes)
                        {
                            string uri = node.Attributes["NodeID"].Value;
                            css.DeleteBranches(new string[] { uri }, rootIterationNode.Uri);
                        }

                    }
                }
            }
        }

    }
}
